#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   trustrank.py    
@Contact :   raogx.vip@hotmail.com
@License :   (C)Copyright 2017-2018, Liugroup-NLPR-CASIA

@Modify Time      @Author    @Version    @Desciption
------------      -------    --------    -----------
2022/10/7 17:23   gxrao      1.0         None
'''

# import lib
import unittest
# 1.导入必要的库
import numpy as np
import random
import math
import operator
from collections import defaultdict

# function to get dict of edges(获取边字典的函数)
def get_dict_of_edges(data_file):
    list_of_edges = []
    edges = defaultdict(list)       # 当key不存在时，返回的是工厂函数的默认值，list对应[ ]

    with open(data_file, 'r') as file:
        list_of_edges = file.readlines()
    for line in list_of_edges:
        src, dst = line.split(' ')          # src源点(source),dst目的地(destination)
        src, dst = int(src), int(dst[:-1])
        if src not in nodes:
            nodes.append(src)
        if dst not in nodes:
            nodes.append(dst)
        edges[src].append(dst)
    return edges

# 2.从graph.txt文件中获取输入并将其转换为邻接表
nodes = []

# dict_of_edges is a dict that contains the adjacency list representation  (Dict_of_edges是一个包含邻接表表示法的字典)
dict_of_edges = get_dict_of_edges('graph.txt')

#init the Transition matrix and the vector (初始化 转移矩阵T 和 向量v)
T = np.zeros((len(nodes), len(nodes)))  # 两个网页之间的转移矩阵
v = np.zeros(len(nodes))                # 一个网页的分数


# Defining the Transition matrix (定义转换矩阵T)
for src_node in dict_of_edges:
    length = len(dict_of_edges[src_node])
    for dst_node in dict_of_edges[src_node]:
        T[dst_node][src_node] = 1/length        # T(dst,src) = 1 / len(src_edges)

# 3.随机初始化50个节点为好节点，50个节点为坏节点，其余节点为中性节点
good = 50 # 50 good nodes
bad = 50 # 50 bad nodes

v = good * [1] + bad * [0] + (4039 - good - bad) * [0.5]    # 初始化时：前50个为1（好节点），接着50个0（坏节点），剩下的0.5（中性节点）
random.shuffle(v)   # random shuffling the good and the bad nodes (随机打乱好节点和坏节点)
v = v/np.sum(v)     # normalizing the vector to have sum of elements = 1 (对向量进行规范化，使其元素之和为1)

# 在迭代算法开始之前初始TrustRank分数向量
print("初始TrustRank分数向量：")
print(v)
# 和预期一样，它的和应该是1
print("v.sum = ")
print(v.sum())

# 4.将阻尼因子设为0.85，迭代直到收敛
b = 0.85  # value of damping factor
temp = v
t = v
t = b * np.dot(T, t) + (1 - b) * v
i = 1  # number of iterations

while np.linalg.norm(temp - t) > 0:  # iterate till the vector converges
    temp = t
    t = b * np.dot(T, t) + (1 - b) * v
    i = i + 1

print("Number of iterations to converge: {}".format(i))  # print the number of iterations

trust_rank_node_score = []  # to store the node and the corresponding trustrank score
for k in range(1, len(t)):
    if t[k] != 0:
        trust_rank_node_score.append([k, t[k]])

# sort the trustrank scores in the decreasing order (将trustrank分数按递减顺序排序)
trust_rank_node_score = sorted(trust_rank_node_score, key=operator.itemgetter(1), reverse=True)

# 转换矩阵
print('T:')
print(T)
# 收敛后每个节点的最终TrustRank得分
print('t:')
print(t)

# 5.节点以及它们的TrustRank分数，按降序排列
# 格式:[Node_number, TrustRank score]
print("trust_rank_node_score(节点以及它们的TrustRank分数，按降序排列):")
print(trust_rank_node_score)

class test(unittest.TestCase):
    def test(self):
        print()

        print('test over')


# 注意如果用windows运行程序的话，要加if __name__ == '__main__':才能正常运行
if __name__ == '__main__':
    unittest.main()
    print('over')
